
#include <sstream>
#include <X11/keysym.h>

#include "window_manager.h"
#include "singleton.h"
#include "WindowCreator.h"


Logger WindowManager::m_log;


WindowManager::WindowManager(){
}

WindowManager::~WindowManager(){
}

void WindowManager::log(const char *str)
{
	m_log.write(str);
}

/**
*	\brief initialize the windows manager
*	\details Open a X server and computes the number of connected screens 
*/
void WindowManager::start(){
	int i;
	int nb_screens;

	m_log.write("The window manager is starting...");
	p_display = XOpenDisplay(NULL);	
	if(p_display == NULL){
		m_log.write("Error connecting to X server");
		throw WindowManagerException();
	}
        
        WindowCreator::getInstance()->attachDisplay(p_display);

	// Computes the number of connected screens
	nb_screens = XScreenCount(p_display);

        WMScreen *screen=NULL;
	// For each screen, create an associated virtual screen
	for(i=0; i<nb_screens; i++){
                log("Create a new screen");  
		screen = new WMScreen(i, p_display);
		m_screens_list.insertLast(screen);
	}
        p_current_screen = screen;

	std::ostringstream str;
	str << "screens = " << m_screens_list.size(); 
	m_log.write(str.str());
        
        p_current_screen->getCurrentMonitor()->spawnWindow("/usr/bin/xterm");
        

	XSetWindowAttributes wa;
	Window root = RootWindow(p_display, 0);
	// Enables ConfigureRequest, MapRequest and ButtonPressed events
	wa.event_mask = SubstructureRedirectMask | ButtonPressMask | SubstructureNotifyMask ;
	XChangeWindowAttributes(p_display, root, CWEventMask, &wa);
        XGrabKey(p_display, 38, AnyModifier, root, True, GrabModeAsync, 
             GrabModeAsync);
}


void WindowManager::run(){

	// Creates an event and loop 
	XEvent ev;
	XSync(p_display, False);

	m_is_running = true;
        
	while(m_is_running){
		XNextEvent(p_display, &ev);
		switch(ev.type){
                        // A window has been created
                        case CreateNotify:
                                createNotify(&ev);
                        break;
                        // A window has been destroyed.
                        case DestroyNotify:
                                destroyNotify(&ev);
                        break;
                        // A window is asking for configuration
			case ConfigureRequest:
                                configureRequest(&ev);
			break;	
			case MapRequest:
				mapRequest(&ev);
			break;	
                        // A keyboard key has been pressed
			case KeyPress:
				keyPress(&ev);
			break;	
		}
	}
}


// Stop the main loop.
void WindowManager::stop(){
	m_is_running = false;
}

// Close the connection with the server
void WindowManager::quit()
{
		m_log.write("Closing window manager...");
		XCloseDisplay(p_display);
}



//*****************************************************************************/
//*                               EVENT HANDLERS                              */
//*****************************************************************************/


/**
* If a window has been created
*/
void WindowManager::createNotify(XEvent *ev)
{
		XCreateWindowEvent *we = &ev->xcreatewindow;
                log("A window has been created");
                //WMWindow *newWindow = new WMWindow(we->window, p_display);
                WindowCreator::getInstance()->create(we->window, p_current_screen, p_current_screen->getCurrentMonitor());
}

/**
* If a window has been destroyed
*/
void WindowManager::destroyNotify(XEvent *ev)
{
		XDestroyWindowEvent *we = &ev->xdestroywindow;
                log("A window has been destroyed");
             
                WindowCreator::getInstance()->destroy(we->window);
}

/**
* If a window is asking to be configured
*/
void WindowManager::configureRequest(XEvent *ev)
{
		XConfigureRequestEvent *we = &ev->xconfigurerequest;

		XWindowChanges wc;
		wc.x = we->x;
		wc.y = we->y;
		wc.width = we->width;
		wc.height = we->height;
		wc.border_width = we->border_width;
		wc.sibling = we->above;
		wc.stack_mode = we->detail;
		XConfigureWindow(p_display, we->window, we->value_mask, &wc);
}


/**
* If a window is asking to be mapped (displayed)
*/
void WindowManager::mapRequest(XEvent *ev)
{
		XMapRequestEvent *we = &ev->xmaprequest;
		XMapWindow(p_display, we->window);
                
                //WMWindow *w = 
                WindowCreator::getInstance()->get(we->window);
                //w->resize(1366,768);
                //w->move(0,0);
}


/**
* If a key has been pressed.
*/ 
void WindowManager::keyPress(XEvent *ev)
{
		int keysym;
                int keysyms_per_keycode_return;
		XKeyPressedEvent *we = &ev->xkey;
                
                keysym = *XGetKeyboardMapping(p_display,we->keycode,1, &keysyms_per_keycode_return);
                
		if(keysym == XK_q)
			stop();	
}